<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.9.4"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Flow-IPC: Sessions: Setting Up an IPC Context</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr id="projectrow">
  <td id="projectalign">
   <div id="projectname">Flow-IPC<span id="projectnumber">&#160;2.0.0</span>
   </div>
   <div id="projectbrief">Flow-IPC project: Full implementation reference.</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.9.4 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search",'Search','.html');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(function() {
  initMenu('',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
/* @license-end */
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

</div><!-- top -->
<div><div class="header">
  <div class="headertitle"><div class="title">Sessions: Setting Up an IPC Context </div></div>
</div><!--header-->
<div class="contents">
<div class="textblock"><center><b>MANUAL NAVIGATION:</b> <a class="el" href="async_loop.html">Preceding Page</a> - <a class="el" href="chan_open.html">Next Page</a> - <a href="./pages.html"><b>Table of Contents</b></a> - <a class="el" href="namespaceipc.html"><b>Reference</b></a></center><hr  />
<p >Let's learn how to set up your first process-to-process session, from which it is easy to create communication channels. (Or go back to preceding page: <a class="el" href="async_loop.html">Asynchronicity and Integrating with Your Event Loop</a>.)</p>
<p >The structure of this page and the next few pages of the Manual is a top-down exploration of what is involved in using Flow-IPC in a typical way. It is, in a way, a tutorial. It will skip topics in aid of exposition and make certain explicit assumptions for the same reason. (We will cover the skipped topics and challenge those assumptions later in the Manual. The Reference of any given API, especially classes and class templates, is also comprehensive.)</p>
<h2>What's a session? Is it necessary? </h2>
<p >The short answers:</p><ul>
<li>If <b>process</b> A (instance of <b>application</b> Ap) wants to speak to (engage in IPC with) process B (of application Bp), they set up a single <b>session</b> together. Each peer process maintains a <a class="el" href="classipc_1_1session_1_1Session.html">Session</a> object. The session is a context for further IPC activities, so that it is easy to open <b>channels</b> for sending messages (and, if desired for advanced cases, to access shared memory arenas) without worrying about naming of individual resources or their cleanup in case IPC is finished (gracefully or otherwise). This provides major value/eliminates a large number of annoying worries that come with typical use of IPC primitives.</li>
<li>It is not <em>necessary</em>. However it is strongly recommended. In general Flow-IPC is structured in such a way as to provide access to whichever layer (level) of IPC the user desires. Typically, though, one should use the highest-level abstractions available, unless there is a specific good reason to go lower.</li>
</ul>
<p >This concept is simple enough <em>once the session is open</em>. In that state, the capabilities of each side of the session (i.e., the <code>Session</code> object in each mutually opposing process) are generally identical. At that stage the fun begins, and that's where we want to get in this tutorial. However to get there things are by necessity somewhat asymmetrical. Let's now discuss the procedures involved in <em>starting</em> a session, so that in the next Manual page we can get to the fun part of ever-so-symmetrically using the now-open session.</p>
<h2>Session-client, session-server paradigm </h2>
<p >For purposes of this tutorial let's deal with the simplest possible situation: application Ap and application Bp want to enage in IPC; this is called an IPC <b>split</b>, in that it can be thought of as a <em>meta-application</em> ApBp being "split" into two parts. A given application Xp is either not running at all (<b>inactive</b>), or it is running 1 process (a/k/a <b>instance</b>) X, or more than 1 process/instance simultaneously (X1, X2, ...). It is quite common for some applications to only have 1 active instance at a time; but it's not true of all applications. It is of course completely common for instances to run serially: X1 starts, then exits; then X2 starts, then exits; and of course there can be combinations.</p>
<p >It <em>is</em> possible (and supported by Flow-IPC) that an application is part of more than 1 split (e.g., Ap-Bp-Cp involves 2 splits). For this tutorial we will not pursue this possibility (we will cover that topic separately later: <a class="el" href="universes.html">Multi-split Universes</a>).</p>
<p >In a given Ap-Bp split, in the <a class="el" href="namespaceipc_1_1session.html" title="Flow-IPC module providing the broad lifecycle and shared-resource organization – via the session conc...">ipc::session</a> paradigm, you must make one major decision which is to assign one the role of the <b>session-server</b>, the other the <b>session-client</b>. (These roles have absolutely no bearing on which &ndash; if any &ndash; is a server or client in <em>any</em> other sense, once a session is open. This only matters, to the vast majority of Flow-IPC, during the session-opening procedure.) By convention we will assign Ap to be server, Bp client in this tutorial. How should you make this decision though?</p>
<p >Answer: In a <em>given</em> split, the only limitation is: at a given time, there can be <em>at most one active instance of a session-server</em>, but there (at your option) can be <em>any number of active instances of a session-client</em>. If in your meta-application there is at most one active instance of either application, then the choice does not matter; just pick one. That said you might consider which one (in the given split) is likelier to require multiple concurrent instances in the future.</p>
<p >For our purposes let's assume we've chosen application Ap (server) and Bp (client).</p>
<p ><a class="anchor" id="universe_desc"></a></p><h2>Specifying IPC universe description: <a class="el" href="structipc_1_1session_1_1App.html" title="A description of an application in this ipc::session inter-process communication universe.">ipc::session::App</a> </h2>
<p >Conceptually, Ap and Bp are both <b>applications</b>, so each has certain basic properties (such as executable name). In addition, Ap takes the role of a server in our split, while Bp takes the role of a client; and in that role Ap has certain additional server-only properties (such as a list of client applications that may establish sessions with it &ndash; in our case just Bp). In order for <a class="el" href="classipc_1_1session_1_1Session.html" title="A documentation-only concept defining the local side of an IPC conversation (session) with another en...">ipc::session::Session</a> hierarchy to work properly when establishing a session, you must provide all of that information to it. This is done very straightforwardly by filling out simple <code>struct</code>s of types <a class="el" href="structipc_1_1session_1_1App.html" title="A description of an application in this ipc::session inter-process communication universe.">ipc::session::App</a>, <a class="el" href="structipc_1_1session_1_1Client__app.html">Client_app</a>, and <a class="el" href="structipc_1_1session_1_1Server__app.html">Server_app</a>. Together these are are the <b>IPC universe description</b>.</p>
<p >To avoid confusion and errors down the line it is important to keep to a simple rule (which is nevertheless tempting to break): The IPC universe description (the <code>App</code>s/<code>Client_app</code>s/<code>Server_app</code>s combined) may be a simple and small thing, but there is conceptually <em>only one</em> of it. So when various little parts of that universe are passed-in to (most notably) <code>Session_server</code> and <code>Client_session</code> constructors, their values must never conflict; they must be equal on each side. So if application Ap lives at "/bin/a.exec" and has UID 322, then both application Ap and application Bp must know those property values for application Ap &ndash; as must application Cp, if it's also a part of the universe. We'll show this more practically below, but just remember this rule.</p>
<p >There are various trivial ways of accomplishing this, but the bottom line is: for code reuse and avoiding mistakes there should be only one piece of code creating and filling out these <code>struct</code>s and containers thereof, with the same values; then each of A and B shall invoke that code; then on each side they'll be used in various capacities, passed-in to <a class="el" href="classipc_1_1session_1_1Session.html" title="A documentation-only concept defining the local side of an IPC conversation (session) with another en...">ipc::session::Session</a> hierarchy objects, so that sessions might open properly. E.g., this <code>struct</code>/etc.-building code can be in an exported function in a static library shared by applications Ap and Bp; or they can be inlined in a header <code>#include</code>d by both; or some other such technique. It may be tempting to skip this nicety, but don't; you don't want to maintain 2+ sets of copy/pasted code that must be kept synced.</p>
<p >Back to our simple Ap-Bp IPC-universe. Step one is to define the applications involved. That's simple for us, as there are only two. Regardless of how many there are, there is no implicit need to collect them in any container &ndash; one must merely define them individually.</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <a class="code hl_struct" href="structipc_1_1session_1_1App.html">ipc::session::App</a> APP_A{ <span class="stringliteral">&quot;a&quot;</span>, <span class="comment">// m_name: The key by which this application is otherwise referred.  Keep it short and sweet.</span></div>
<div class="line">                               <span class="stringliteral">&quot;/bin/app_a.exec&quot;</span>, <span class="comment">// m_exec_path: The exact path via which it&#39;s invoked from command line or run script.</span></div>
<div class="line">                               USER_ID, <span class="comment">// m_user_id: This app&#39;s effective user ID when invoked.  See below.</span></div>
<div class="line">                               GROUP_ID }; <span class="comment">// m_group_id: This app&#39;s effective owner group ID when invoked.  See below.</span></div>
<div class="line"><span class="keyword">const</span> <a class="code hl_struct" href="structipc_1_1session_1_1App.html">ipc::session::App</a> APP_B{ <span class="stringliteral">&quot;b&quot;</span>,</div>
<div class="line">                               <span class="stringliteral">&quot;/bin/app_b.exec&quot;</span>,</div>
<div class="line">                               USER_ID,</div>
<div class="line">                               GROUP_ID };</div>
<div class="ttc" id="astructipc_1_1session_1_1App_html"><div class="ttname"><a href="structipc_1_1session_1_1App.html">ipc::session::App</a></div><div class="ttdoc">A description of an application in this ipc::session inter-process communication universe.</div><div class="ttdef"><b>Definition:</b> <a href="app_8hpp_source.html#l00077">app.hpp:78</a></div></div>
</div><!-- fragment --><p >In this example the two apps share a user (user so-and-so, group so-and-so) for simplicity and therefore specify the same values there. This is by no means a requirement. (See <a class="el" href="safety_perms.html">Safety and Permissions</a> for other, potentially more safety-robust production approaches.)</p>
<p >Step two is to define all the applications that take on (at least) a session-client role; each needs a <code>Client_app</code> object. In our case that is just Bp. As a session-client, Bp <em>is</em> <code>App</code> Bp; so it shall have a copy thereof inside it; in fact <code>Client_app</code> sub-classes <code>App</code>. As of this writing it lacks any additional data as a client; so it's just:</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <a class="code hl_struct" href="structipc_1_1session_1_1Client__app.html">ipc::session::Client_app</a> APP_B_AS_CLI{ APP_B };</div>
<div class="ttc" id="astructipc_1_1session_1_1Client__app_html"><div class="ttname"><a href="structipc_1_1session_1_1Client__app.html">ipc::session::Client_app</a></div><div class="ttdoc">An App that is used as a client in at least one client-server IPC split.</div><div class="ttdef"><b>Definition:</b> <a href="app_8hpp_source.html#l00184">app.hpp:185</a></div></div>
</div><!-- fragment --><p >All client-apps must also be collected in a container for a certain purpose that we'll soon reveal. We have just the one, so:</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <a class="code hl_typedef" href="structipc_1_1session_1_1Client__app.html#add718cbf6aa1d2abb26fbadcc974a7bd">ipc::session::Client_app::Master_set</a> MASTER_APPS_AS_CLI{ { APP_B_AS_CLI.m_name, APP_B_AS_CLI } };</div>
<div class="line"><span class="comment">// If there were more clients, we&#39;d add them to the map-initializing list in braces.  Note the use of App::m_name as a key; `App`s themselves are never used as keys.</span></div>
<div class="ttc" id="astructipc_1_1session_1_1Client__app_html_add718cbf6aa1d2abb26fbadcc974a7bd"><div class="ttname"><a href="structipc_1_1session_1_1Client__app.html#add718cbf6aa1d2abb26fbadcc974a7bd">ipc::session::Client_app::Master_set</a></div><div class="ttdeci">boost::unordered_map&lt; std::string, Client_app &gt; Master_set</div><div class="ttdoc">Suggested type for storing master repository or all Client_appss. See App doc header for discussion.</div><div class="ttdef"><b>Definition:</b> <a href="app_8hpp_source.html#l00192">app.hpp:192</a></div></div>
</div><!-- fragment --><p >Step three is to define all the applications that take on (at least) a session-server role; each needs a <code>Server_app</code> object. In our case that is just Ap. As a session-server, Ap <em>is</em> <code>App</code> Ap; so it shall have a copy thereof inside it; <code>Server_app</code> sub-classes <code>App</code>. It also has a couple other attributes which must be set, notably those <code>Client_app</code>s that are allowed to open sessions with it; in our case that's just Bp. There is no need to collect them in a container. Thus:</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <a class="code hl_struct" href="structipc_1_1session_1_1Server__app.html">ipc::session::Server_app</a> APP_A_AS_SRV{ APP_A, <span class="comment">// Super-class App: Copy the App info.</span></div>
<div class="line">                                             { APP_B.<a class="code hl_variable" href="structipc_1_1session_1_1App.html#a8e67b57829fe43a122a23c699b5de8fd">m_name</a> }, <span class="comment">// m_allowed_client_apps: The apps that can open sessions with us.  Note the use of App::m_name: it&#39;s a key.</span></div>
<div class="line">                                             <span class="stringliteral">&quot;&quot;</span>, <span class="comment">// m_kernel_persistent_run_dir_override: Leave default so the customary /var/run is used to store PID files and the like.</span></div>
<div class="line">                                             <a class="code hl_enumvalue" href="namespaceipc_1_1util.html#a2ec0bfdddb41a1ef0403e4bb8967705daa3e1d310128f18fe2f903bf3cba8849a">ipc::util::Permissions_level::S_USER_ACCESS</a> }; <span class="comment">// m_permissions_level_for_client_apps: See below.</span></div>
<div class="ttc" id="anamespaceipc_1_1util_html_a2ec0bfdddb41a1ef0403e4bb8967705daa3e1d310128f18fe2f903bf3cba8849a"><div class="ttname"><a href="namespaceipc_1_1util.html#a2ec0bfdddb41a1ef0403e4bb8967705daa3e1d310128f18fe2f903bf3cba8849a">ipc::util::Permissions_level::S_USER_ACCESS</a></div><div class="ttdeci">@ S_USER_ACCESS</div><div class="ttdoc">Allows access by resource-owning user (in POSIX/Unix identified by UID) and no one else.</div></div>
<div class="ttc" id="astructipc_1_1session_1_1App_html_a8e67b57829fe43a122a23c699b5de8fd"><div class="ttname"><a href="structipc_1_1session_1_1App.html#a8e67b57829fe43a122a23c699b5de8fd">ipc::session::App::m_name</a></div><div class="ttdeci">std::string m_name</div><div class="ttdoc">Brief application name, readable to humans and unique across all other applications' names; used both...</div><div class="ttdef"><b>Definition:</b> <a href="app_8hpp_source.html#l00144">app.hpp:144</a></div></div>
<div class="ttc" id="astructipc_1_1session_1_1Server__app_html"><div class="ttname"><a href="structipc_1_1session_1_1Server__app.html">ipc::session::Server_app</a></div><div class="ttdoc">An App that is used as a server in at least one client-server IPC split.</div><div class="ttdef"><b>Definition:</b> <a href="app_8hpp_source.html#l00205">app.hpp:206</a></div></div>
</div><!-- fragment --><p >We use USER_ACCESS permissions-level, because all our apps share an effective user. (See <a class="el" href="safety_perms.html">Safety and Permissions</a> for more information and more safety-robust setups.)</p>
<p >That's it. That's our IPC universe description: the <code>App</code>s, the <code>Client_app</code>s (collected in a container), and the <code>Server_app</code>s. It may be tempting, since our situation is so simple, to skip some things &ndash; e.g., we could skip separately defining <code>App</code>s and copying them into <code>Client_app</code> and <code>Server_app</code>/rather just define the latter 2 items &ndash; but the performance/RAM impact of doing the whole thing is negligible, while in the long run keeping it clean this way will only help when/if your IPC universe becomes more complex.</p>
<p >You should run all 3 steps in each of Ap and Bp, thus ending up with the same data structures. You are now ready to start some sessions; or at least a session.</p>
<h2>Lifecycle of process versus lifecycle of session: Overview </h2>
<dl class="section note"><dt>Note</dt><dd>Firstly let us assume, for simplicity of discussion, that each of your applications, through ~100% of its existence and to enable ~100% of its functionality, requires IPC capabilities. In reality this is of course not a requirement; it may operate degraded before/between/after IPC sessions, or whatever. We just consider that irrelevant to the discussion, and it is annoying and confusing to keep mentioning the caveat. Having assumed that:</dd></dl>
<p>The IPC-related lifecycle of any session-client process is particularly simple:</p><ol type="1">
<li>Start.</li>
<li>Create the <a class="el" href="session_setup.html#universe_desc">IPC universe description</a>.</li>
<li>Construct <a class="el" href="namespaceipc_1_1session.html#a77d8fda00e1e17f595a6a5d4c44375e7">Client_session C</a> (ideally SHM-backed extension thereof); and <code>C.sync_connect()</code> to the server.<ol type="a">
<li>If this fails, server is likely inactive; hence sleep perhaps a second; then retry&lowast;&lowast;. Repeat until success.</li>
</ol>
</li>
<li>Engage in IPC via now-open <code>Session C</code> until (gracefully) told to exit (such as via SIGINT/SIGTERM)&lowast;; or:</li>
<li>Is informed by <code>Session C</code> on-error handler that the session was closed by the opposing side; therefore:<ol type="a">
<li>Destroy <code>C</code>.</li>
<li>Go back to step 3.</li>
</ol>
</li>
</ol>
<p >&lowast; - In this case destroy <code>C</code> and exit process.<br  />
 &lowast;&lowast; - See <a class="el" href="classipc_1_1session_1_1Client__session__mv.html#ab971ea979200828d572638c60d7d9f44">Client_session::sync_connect() Reference doc</a> note regarding dealing with inactive opposing server.</p>
<p >Thus a typical session-client is, as far as IPC is concerned, always either trying to open a session or is engaging in IPC via exactly one open session; and it only stops doing the latter if it itself exits entirely; or the session is closed by the opposing side. There is, in production, no known good reason to end a session otherwise nor to create simultaneous 2+ <code>Client_session</code>s in one process.</p>
<p >The IPC-related lifecycle of a session-server can be more complex. In the simplest case, wherein you've decided the session-server only needs to speak to one opposing process at a time (for this split), it is very much like the session-client:</p><ol type="1">
<li>Start.</li>
<li>Create the <a class="el" href="session_setup.html#universe_desc">IPC universe description</a>.</li>
<li>Construct <a class="el" href="classipc_1_1session_1_1Session__server.html">P</a>.</li>
<li>Await an opened session via <code>P.async_accept()</code> which on success yields <code>Server_session S</code>.<ol type="a">
<li>If this fails, that's highly unusual. Just try again. Normally it will just sit there until a <code>Client_session</code> attempts to connect.</li>
<li>On success:</li>
</ol>
</li>
<li>Engage in IPC via now-open <code>Session S</code> until (gracefully) told to exit (such as via SIGINT/SIGTERM); or:</li>
<li>Is informed by <code>Session S</code> on-error handler that the session was closed by the opposing side; therefore:<ol type="a">
<li>Destroy <code>S</code>.</li>
<li>Go back to step 4.</li>
</ol>
</li>
</ol>
<p >However if your application desires to indeed support multiple <em>concurrent</em> sessions then it shall act more like an actual server as opposed to just a glorified client. Namely, the real difference is that upon <code>P.async_accept()</code> success, conceptually it should &ndash; as opposed to merely engaging in IPC off the new session &ndash; kick off two algorithms simultaneously:</p><ul>
<li>Go back to step 4 in which it again begins an async (possibly quite long-lasting) <code>P.async_accept()</code>.</li>
<li>Engage in IPC off the new session that was just accepted. Accordingly, in step 6.b, it should not "go back to step 4" but rather just end the algorithm in the latter bullet point: There is always a session-accept in progress, and 1 <em>or more</em> sessions may be operating concurrently as well. (To be clear by "concurrently" we don't mean necessarily simultaneously in 2+ threads; but rather that an asynchronously-oriented application can conceptually perform 2+ simultaneous algorithms even in one thread.)</li>
</ul>
<h2><code>Client_session</code> setup </h2>
<p >Let's now follow the above outline for a session-client's operation, the client being application Bp. We shall skip to step 3, as we've already covered step 2.</p>
<p ><code>Client_session</code> is a class template, not a class, and moreover extensions like <code>shm::classic::Client_session</code> exist. The choice of actual concrete type is quite important. First of all decide whether you desire to work with SHM-backed channels and/or SHM arenas; and if so what kind. Simply put our recommendation:</p><ul>
<li>For maximum performance you <em>should</em> choose a SHM-backed session type. Using vanilla <code>Client_session</code> is giving away performance for no good reason.</li>
<li>What kind? That is outside the scope of this page but is discussed elsewhere in the Manual. You'll get zero-copy performance either way so for now, at least for simplicity:<ul>
<li>Let us choose SHM-classic; hence the specific template to use is <a class="el" href="namespaceipc_1_1session_1_1shm_1_1classic.html#ac6c443a72e0f22710c83bb1e8c229618" title="This is to session::Client_session what shm::classic::Server_session is to session::Server_session.">ipc::session::shm::classic::Client_session</a>. We strongly recommend, at this stage, defining an alias template that incorporates the details of your decision, so they need not be mentioned again later in your code:</li>
</ul>
</li>
</ul>
<div class="fragment"><div class="line"><span class="keyword">template</span>&lt;ipc::session::schema::MqType S_MQ_TYPE_OR_NONE, <span class="keywordtype">bool</span> S_TRANSMIT_NATIVE_HANDLES,</div>
<div class="line">         <span class="keyword">typename</span> Mdt_payload = ::capnp::Void&gt;</div>
<div class="line"><span class="keyword">using </span>Client_session_t = <a class="code hl_class" href="classipc_1_1session_1_1shm_1_1classic_1_1Session__mv.html">ipc::session::shm::classic::Client_session&lt;S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload&gt;</a>;</div>
<div class="line"><span class="comment">// By the way... for all future mentions of Error_code:</span></div>
<div class="line"><span class="keyword">using </span><a class="code hl_typedef" href="namespaceipc.html#aa3192e586cc45d3e7c22463bf2760f89">Error_code</a> = <a class="code hl_typedef" href="namespaceipc.html#aa3192e586cc45d3e7c22463bf2760f89">ipc::Error_code</a>;</div>
<div class="ttc" id="aclassipc_1_1session_1_1shm_1_1classic_1_1Session__mv_html"><div class="ttname"><a href="classipc_1_1session_1_1shm_1_1classic_1_1Session__mv.html">ipc::session::shm::classic::Session_mv</a></div><div class="ttdoc">Implements the SHM-related API common to shm::classic::Server_session and shm::classic::Client_sessio...</div><div class="ttdef"><b>Definition:</b> <a href="ipc__shm_2src_2ipc_2session_2shm_2classic_2session_8hpp_source.html#l00042">session.hpp:44</a></div></div>
<div class="ttc" id="anamespaceipc_html_aa3192e586cc45d3e7c22463bf2760f89"><div class="ttname"><a href="namespaceipc.html#aa3192e586cc45d3e7c22463bf2760f89">ipc::Error_code</a></div><div class="ttdeci">flow::Error_code Error_code</div><div class="ttdoc">Short-hand for flow::Error_code which is very common.</div><div class="ttdef"><b>Definition:</b> <a href="common_8hpp_source.html#l00298">common.hpp:298</a></div></div>
</div><!-- fragment --><p >Next let's decide on the values for those 3 template parameters. The first two determine the concrete type of <a class="el" href="classipc_1_1transport_1_1Channel.html" title="Peer to a bundle of 1-2 full-duplex pipe(s), one for transmitting unstructured binary blobs; the othe...">ipc::transport::Channel</a> that shall be opened in this session. The last template parameter is used for certain advanced purposes around channel-opening. We'll talk about all of those topics in <a class="el" href="chan_open.html">Sessions: Opening Channels</a>. For now we'll forego the advanced-metadata stuff (leave that arg at default), and we'll choose a sufficiently powerful and performant setting for the former 2 params. Thus, again, we strongly recommend to define the concrete type in an alias, so that the details need not be repeated subsequently.</p>
<div class="fragment"><div class="line"><span class="comment">// Each channel shall contain (only) a (bidirectional) Unix domain stream socket, capable of transmitting data and native handles.</span></div>
<div class="line"><span class="comment">// This is sufficient for all purposes in terms of what it can transmit; and can only be potentially improved upon -- likely marginally</span></div>
<div class="line"><span class="comment">// at best -- in terms of performance by adding POSIX or bipc MQ pipes as well.</span></div>
<div class="line"><span class="keyword">using </span>Session = Client_session_t&lt;ipc::session::schema::MqType::NONE, true&gt;;</div>
</div><!-- fragment --><p >So now we can construct our <code>Client_session</code> (which we named just <code>Session</code> since, once it's open, its capabilities are ~identical to the opposing process's counterpart). We can use one of 2 constructors: one that allows subsequent channel passive-opens; the other which does not. Let's use the latter, as it's slightly simpler. (We'll get into that topic in <a class="el" href="chan_open.html">Sessions: Opening Channels</a>. For now don't worry.)</p>
<div class="fragment"><div class="line">Session <span class="comment">// Use the alias we have set up.</span></div>
<div class="line">  session(..., <span class="comment">// Logger.</span></div>
<div class="line">          APP_B_AS_CLI, <span class="comment">// Part of the IPC universe description: Our own info.</span></div>
<div class="line">          APP_A_AS_SRV, <span class="comment">// Part of the IPC universe description: The opposing server&#39;s info.</span></div>
<div class="line">          ...); <span class="comment">// On-error handler (discussed separately).  This is relevant only after sync_connect() success.</span></div>
</div><!-- fragment --><p >Now we can attempt connection via <code>sync_connect()</code>. There are 2 forms, the simple and the advanced. Ironically, due to its ability to pre-open channels, the advanced form is in most cases the <em>easier</em> one to use all-in-all &ndash; it makes it unnecessary to do annoying possibly-async channel-opening later &ndash; but we aren't talking about channel opening yet, so that part is not relevant; hence for now we'll go with the simpler API. (<a class="el" href="chan_open.html">Sessions: Opening Channels</a> gets into all that.)</p>
<p >Using it is simple:</p>
<div class="fragment"><div class="line"><span class="comment">// Thread U.</span></div>
<div class="line"><a class="code hl_typedef" href="namespaceipc.html#aa3192e586cc45d3e7c22463bf2760f89">Error_code</a> err_code;</div>
<div class="line">session.sync_connect(&amp;err_code);</div>
<div class="line"><span class="keywordflow">if</span> (err_code)</div>
<div class="line">{</div>
<div class="line">  <span class="comment">// sync_connect() failed.  Assuming everything is configured okay, this would usually only happen</span></div>
<div class="line">  <span class="comment">// if the opposing server is currently inactive.  Therefore it&#39;s not a great idea to immediately</span></div>
<div class="line">  <span class="comment">// sync_connect() again.  A reasonable plan is to schedule another attempt in 250-5000ms.</span></div>
<div class="line"> </div>
<div class="line">  <span class="comment">// ...;</span></div>
<div class="line">  <span class="keywordflow">return</span>;</div>
<div class="line">}</div>
<div class="line"><span class="comment">// else: Success!</span></div>
<div class="line"> </div>
<div class="line"><span class="comment">// Operate on `session` in here, long-term, until it is hosed.  Once it is hosed, probably repeat this</span></div>
<div class="line"><span class="comment">// entire procedure.</span></div>
<div class="line">go_do_ipc_yay(...);</div>
</div><!-- fragment --><h2><code>Session_server</code> and <code>Server_session</code> setup </h2>
<p >On the server end, accordingly, we accept the connection. The pattern may be familiar for users of boost.asio: There's a server (acceptor) object which, on success, modifies an un-connected peer object. We will use the simpler form of <a class="el" href="classipc_1_1session_1_1Session__server.html#a13887cd64912bb5f5675e2817ff8435f" title="Asynchronously awaits for an opposing Client_session to request session establishment and calls on_do...">ipc::session::Session_server::async_accept()</a> and discuss the other one in (you guessed it) <a class="el" href="chan_open.html">Sessions: Opening Channels</a>.</p>
<dl class="section note"><dt>Note</dt><dd>There is, however, one added step required to get a given server session object to opened state, even once <code>async_accept()</code> has succeeded. One must call <code><a class="el" href="classipc_1_1session_1_1Server__session__mv.html#a99097e5aa6883877c74f8a93ebc9f3e1" title="To be invoked by public user upon first obtaining *this: memorizes the given on-error and on-passive-...">ipc::session::Server_session::init_handlers()</a></code>, whose overloads take certain handler function(s) as arg(s). This is in fact symmetrical to what the <code>Client_session</code> user had to do at construction time as shown above. <code>Server_session</code> does not provide the same in <em>its</em> constructor, because what handlers one may want to install for a given server-session depends on, among other things, which <code>Client_app</code> is in fact connecting to it; it can be any one from <code>MASTER_APPS_AS_CLI</code>, and one cannot time-travel to the future to predict this before <code>async_accept()</code> being called and succeeding.</dd>
<dd>
We discuss the <code>Client_session</code> ctor + <code>Server_session::init_handlers()</code> handler args in <a class="el" href="chan_open.html">Sessions: Opening Channels</a> (the optional passive-channel-open handler) and <a class="el" href="session_app_org.html">Sessions: Teardown; Organizing Your Code</a> (the mandatory error handler).</dd></dl>
<p>In summary then:</p>
<div class="fragment"><div class="line"><span class="comment">// These parameters and the concrete class have to match, at compile time, the opposing Client_session&#39;s.</span></div>
<div class="line"><span class="comment">// Otherwise the session-open will fail with an error indicating the incompatibility.</span></div>
<div class="line"><span class="keyword">template</span>&lt;ipc::session::schema::MqType S_MQ_TYPE_OR_NONE, <span class="keywordtype">bool</span> S_TRANSMIT_NATIVE_HANDLES,</div>
<div class="line">         <span class="keyword">typename</span> Mdt_payload = ::capnp::Void&gt;</div>
<div class="line"><span class="keyword">using </span>Session_server_t = <a class="code hl_class" href="classipc_1_1session_1_1shm_1_1classic_1_1Session__server.html">ipc::session::shm::classic::Session_server&lt;S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload&gt;</a>;</div>
<div class="line"><span class="keyword">using </span>Session_server = Session_server_t&lt;session::schema::MqType::NONE, true&gt;;</div>
<div class="line"><span class="keyword">using </span>Session = Session_server::Server_session_obj; <span class="comment">// This is the mirror image of the opposing process&#39;s Session type.</span></div>
<div class="line"> </div>
<div class="line"><span class="comment">// Thread U.</span></div>
<div class="line"><a class="code hl_typedef" href="namespaceipc.html#aa3192e586cc45d3e7c22463bf2760f89">Error_code</a> err;</div>
<div class="line">Session_server session_srv(..., <span class="comment">// Logger.</span></div>
<div class="line">                           APP_A_AS_SRV, <span class="comment">// Part of the IPC universe description: Our own info (including allowed client apps).</span></div>
<div class="line">                           MASTER_APPS_AS_CLI); <span class="comment">// Part of the IPC universe description: All the client apps in existence.</span></div>
<div class="line"><span class="comment">// We omitted the optional Error_code* arg.  So if it fails it&#39;ll throw exception.</span></div>
<div class="line"><span class="comment">// Looking in ipc::session::shm::classic::Session_server docs we see it lists the following as possible `Error_code`s emitted:</span></div>
<div class="line"><span class="comment">// &quot;interprocess-mutex-related errors (probably from boost.interprocess) w/r/t writing the CNS (PID file); &quot;</span></div>
<div class="line"><span class="comment">//   file-related system errors w/r/t writing the CNS (PID file) (see class doc header for background);</span></div>
<div class="line"><span class="comment">//   errors emitted by transport::Native_socket_stream_acceptor ctor (see that ctor&#39;s doc header; but note</span></div>
<div class="line"><span class="comment">//   that they comprise name-too-long and name-conflict errors which ipc::session specifically exists to</span></div>
<div class="line"><span class="comment">//   avoid, so you need not worry about even the fact there&#39;s an abstract Unix domain socket address involved).&quot;&quot;</span></div>
<div class="line"> </div>
<div class="line">Session session_being_opened; <span class="comment">// Empty session object.</span></div>
<div class="line"> </div>
<div class="line">session_srv.async_accept(&amp;session_being_opened, [...](<span class="keyword">const</span> <a class="code hl_typedef" href="namespaceipc.html#aa3192e586cc45d3e7c22463bf2760f89">Error_code</a>&amp; err_code)</div>
<div class="line">{</div>
<div class="line">  <span class="keywordflow">if</span> (err_code == <a class="code hl_enumvalue" href="namespaceipc_1_1session_1_1error.html#a0708d4bec9ae853f4d7e3d7822fc8f2fafe29343445a7bf167cc186a44bd2c6ed">ipc::session::error::Code::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER</a>)</div>
<div class="line">  {</div>
<div class="line">    <span class="keywordflow">return</span>;</div>
<div class="line">  }</div>
<div class="line"> </div>
<div class="line">  post([..., err_code])() { on_new_session(err_code]); });</div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line"><span class="keywordtype">void</span> on_new_session(<span class="keyword">const</span> <a class="code hl_typedef" href="namespaceipc.html#aa3192e586cc45d3e7c22463bf2760f89">Error_code</a>&amp; err_code)</div>
<div class="line">{</div>
<div class="line">  <span class="comment">// Thread U.</span></div>
<div class="line">  <span class="keywordflow">if</span> (err_code)</div>
<div class="line">  {</div>
<div class="line">    <span class="comment">// async_accept() failed.  This is fairly unusual and worth noting/logging/alerting, as it indicates</span></div>
<div class="line">    <span class="comment">// some kind of setup or environmental or transient problem worth looking into.</span></div>
<div class="line"> </div>
<div class="line">    <span class="comment">// ...</span></div>
<div class="line"> </div>
<div class="line">    <span class="comment">// If you expect only one A-B session at a time (no multiple simultaneous clients), you&#39;d</span></div>
<div class="line">    <span class="comment">// launch the next session-srv.async_accept() here without delay.</span></div>
<div class="line">    <span class="comment">// If you expect 2+ A-B sessions as a possibility, then you&#39;d do so at the end of on_new_session().</span></div>
<div class="line">    <span class="comment">// Your decision.</span></div>
<div class="line">    <span class="comment">// [...]</span></div>
<div class="line">    <span class="keywordflow">return</span>;</div>
<div class="line">  }</div>
<div class="line">  <span class="comment">// else: Success!</span></div>
<div class="line"> </div>
<div class="line">  <span class="comment">// Since session_being_opened may be used for the conceptually-concurrent (to using the newly-opened Session)</span></div>
<div class="line">  <span class="comment">// session-opening algorithm, it&#39;s important to save it into a separate Session object.</span></div>
<div class="line">  <span class="keyword">auto</span> a_session = std::move(session_being_opened);</div>
<div class="line">  <span class="comment">// session_being_opened is now empty again.</span></div>
<div class="line"> </div>
<div class="line">  a_session.init_handlers(...); <span class="comment">// On-error handler (discussed separately).</span></div>
<div class="line"> </div>
<div class="line">  <span class="comment">// Operate on `a_session` in here, long-term, until it is hosed.  Once it is hosed:</span></div>
<div class="line">  <span class="comment">//   - If multiple concurrent sessions allowed: End that algorithm (do nothing other than cleanup).</span></div>
<div class="line">  <span class="comment">//   - Else: launch another session_srv.async_accept() as noted above.</span></div>
<div class="line">  go_do_ipc_yay(std::move(a_session));</div>
<div class="line"> </div>
<div class="line">  <span class="comment">// [...If multiple concurrent sessions allowed: Launch another session_srv.async_accept() here as noted above.]</span></div>
<div class="line">});</div>
<div class="ttc" id="aclassipc_1_1session_1_1shm_1_1classic_1_1Session__server_html"><div class="ttname"><a href="classipc_1_1session_1_1shm_1_1classic_1_1Session__server.html">ipc::session::shm::classic::Session_server</a></div><div class="ttdoc">This is to vanilla Session_server what shm::classic::Server_session is to vanilla Server_session: it ...</div><div class="ttdef"><b>Definition:</b> <a href="ipc__shm_2src_2ipc_2session_2shm_2classic_2session__server_8hpp_source.html#l00070">session_server.hpp:74</a></div></div>
<div class="ttc" id="anamespaceipc_1_1session_1_1error_html_a0708d4bec9ae853f4d7e3d7822fc8f2fafe29343445a7bf167cc186a44bd2c6ed"><div class="ttname"><a href="namespaceipc_1_1session_1_1error.html#a0708d4bec9ae853f4d7e3d7822fc8f2fafe29343445a7bf167cc186a44bd2c6ed">ipc::session::error::Code::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER</a></div><div class="ttdeci">@ S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER</div><div class="ttdoc">Async completion handler is being called prematurely, because underlying object is shutting down,...</div></div>
</div><!-- fragment --><p >In our example code on each side, <code>go_do_ipc_yay()</code> now has an equally-capable <code>Session</code> object which represents a shared IPC context through which to, broadly, open channels and (optionally) directly access SHM arena(s). Via the open channels, in turn, one can send messages (covered later in the Manual when we discuss <a class="el" href="namespaceipc_1_1transport.html" title="Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...">ipc::transport</a>). Via the SHM arena(s) one can allocate objects (which can be shared however one wants but most easily via <a class="el" href="namespaceipc_1_1transport.html" title="Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...">ipc::transport</a> channels as well).</p>
<p >Next let's discuss <a class="el" href="chan_open.html">Sessions: Opening Channels</a>.</p>
<hr  />
<center><b>MANUAL NAVIGATION:</b> <a class="el" href="async_loop.html">Preceding Page</a> - <a class="el" href="chan_open.html">Next Page</a> - <a href="./pages.html"><b>Table of Contents</b></a> - <a class="el" href="namespaceipc.html"><b>Reference</b></a></center> </div></div><!-- contents -->
</div><!-- PageDoc -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 11 2025 20:02:26 for Flow-IPC by&#160;<a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.4
</small></address>
</body>
</html>
